package org.softee.numbertext;

import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.Arrays;
import java.util.Locale;

public abstract class NumberText {
    static final boolean PAD_DECIMALS = true;
    protected static final String SPACE = " ";
    protected static final BigInteger BIG_THOUSAND = BigInteger.valueOf(1000);

    private static enum LocaleNumberText {
        DA(new NumberTextDa()),
        EN_US(new NumberTextEn()),
        EN(new NumberTextEn());
        public final NumberText numberText;

        private LocaleNumberText(NumberText numberText) {
            this.numberText = numberText;
        }
    }

    private final String minus;

    public NumberText(String minus) {
        this.minus = minus;
    }

    public String format(BigInteger number) {
        if (number.signum() < 0) {
            return minus + SPACE + format(number.negate());
        };
        return formatPositive(number);
    }

    protected abstract String formatPositive(BigInteger number);

    public String format(BigDecimal number, int decimals) {
        if (number.signum() < 0) {
            return minus + SPACE + format(number.negate(), decimals);
        };
        final String integerPart = format(number.toBigInteger());
        return integerPart + " " + decimalPart(number, decimals);
    }

    public static NumberText getInstance() {
        return getInstance(Locale.getDefault());
    }

    public static NumberText getInstance(Locale locale) {
        String language = locale.getLanguage().toUpperCase();
        String country = locale.getCountry().toUpperCase();
        LocaleNumberText localeNumberText;
        try {
            localeNumberText = LocaleNumberText.valueOf(language + "_" + country);
        } catch (IllegalArgumentException e) {
            try {
                localeNumberText = LocaleNumberText.valueOf(language);
            } catch (IllegalArgumentException e1) {
                throw new IllegalArgumentException(String.format("No support for %s (%s)", language, country));
            }
        }
        return localeNumberText.numberText;
    }

    public abstract BigDecimal parse(String numberText);

    public String format(long l) {
        return format(BigInteger.valueOf(l));
    }

    protected long checkRange(long i, long minInclusive, long maxInclusive) {
        if (i < minInclusive || i > maxInclusive) {
            throw new IllegalArgumentException(String.format("%d is not in the range (%d .. %d)", i, minInclusive, maxInclusive));
        }
        return i;
    }

    protected String decimalPart(BigDecimal d, int numberOfdecimals) {
        BigDecimal decimalPart = d.remainder(BigDecimal.ONE);
        int decimalValue = decimalPart.scaleByPowerOfTen(numberOfdecimals).intValue();
        String decimals = String.valueOf(decimalValue);
        String decimalsPadded = PAD_DECIMALS ? padLeft(decimals, '0', numberOfdecimals) : decimals;
        String ofPart = "1"  + repeat('0', numberOfdecimals);
        return  decimalsPadded + "/" + ofPart;
    }

    protected String padLeft(String s, char ch, int length) {
        int pad = length - s.length();
        return (pad > 0) ? repeat(ch, pad) + s : s;
    }

    protected String repeat(char ch, int count) {
        char[] chars = new char[count];
        Arrays.fill(chars, ch);
        return String.valueOf(chars);
    }
}
